#include "BcNetIOAndRecvBc.h"

//************************************
// Method:    	RecvNetIOBc_ANA			解析站间广播信息
// Programmer:  lww
// Time:		2019/2/16
// Returns:   	bool					true:接收字节数正确；false：错误
// Parameter: 	void * Data				数据区头指针
// Parameter: 	int len					数据包长度
// Parameter: 	short Head				报头
// Parameter: 	short Tail				报尾
//************************************
bool RecvNetIOBc_ANA(void* Data, int len, short Head, short Tail)
{
#define MEMREAD1(var)	MEMREAD(var, Data)
#define WRONG_DEAL	{\
	printf("Analyze NETIO BC wrong!\r\n");\
	return false;\
}

	int i, j;
	int _iLen = 0;
	short Channel_Num = 0;
	short tmp_short;
	unsigned char Source_Station_Num;
	float tmp_float;
	bool tmp_bool;
	short ptr_off;
	unsigned int Source_Model_ID;
	Channel_type_e type;
	NETAI_T* base_NETAI;
	NETDI_T* base_NETDI;

	//< 校验报头
	MEMREAD1(tmp_short);
	if (tmp_short != Head)
		WRONG_DEAL;

	//< 读出站号
	MEMREAD1(Source_Station_Num);
	if (Source_Station_Num == Station_ID)				//< 不解析本站发送的报文
		return true;

	//< 读出当前指针到报尾的指针的距离，校验报尾
	MEMREAD1(ptr_off);
	memcpy(&tmp_short, (char*)(Data) + ptr_off, sizeof(tmp_short));
	if (tmp_short != Tail)
		WRONG_DEAL;

	//< 接收到的广播点数量
	MEMREAD1(Channel_Num);

	//< 循环解析各个模块
	for (i = 0; i < Channel_Num; i++)
	{
		MEMREAD1(type);
		MEMREAD1(Source_Model_ID);
		if (type == AO_CHA)
		{			
			MEMREAD1(tmp_float);
			for (j = 0; j < Model_List[TYPE(NETAI)].iCount; j++)
			{
				base_NETAI = (NAME(NETAI)*)SearchAt(((List_Base_t*)Model_List[TYPE(NETAI)].ppData[0]), j);
				if (base_NETAI->Par.Source_Station_Num == Source_Station_Num && base_NETAI->Par.Source_Model_ID == Source_Model_ID)
				{
					base_NETAI->Sta.Input_Value = tmp_float;
					base_NETAI->Sta.FailedTime_Count = 0;
				}
			}
		}
		else if (type == DO_CHA)
		{
			MEMREAD1(tmp_bool);
			for (j = 0; j < Model_List[TYPE(NETDI)].iCount; j++)
			{
				base_NETDI = (NAME(NETDI)*)SearchAt(((List_Base_t*)Model_List[TYPE(NETDI)].ppData[0]), j);
				if (base_NETDI->Par.Source_Station_Num == Source_Station_Num && base_NETDI->Par.Source_Model_ID == Source_Model_ID)
				{
					base_NETDI->Sta.Input_Value = tmp_bool;
					base_NETDI->Sta.FailedTime_Count = 0;
				}
			}
		}
		else
		{
			WRONG_DEAL;
		}
	}

	if (_iLen != (int)(len - sizeof(tmp_short)))
		WRONG_DEAL;

	return true;

#undef WRONG_DEAL
#undef MEMREAD1
}


//************************************
// Method:    	tRecvNetIOBc			接收站间广播信息线程
// Programmer:  lww
// Time:		2019/3/6
// Returns:   	void *
// Parameter: 	void * arg
//************************************
void * tRecvNetIOBc(void* arg)
{
#define PACK_MAXNUM	2048

	int sock;
	short Head = 7555;				//< 报头
	short Tail = 7576;				//< 报尾
	char Data2Recv[PACK_MAXNUM];	//< 存放数据包的数组
	short len;

	//< 初始化UDP设置
	if (false == UDP_Init(&sock, RECVNETIOBC_PORT, 0, 0, UDP_RECV_STATUS, nullptr)) { return 0; }

	while (1)
	{
		//< 接收数据
		memset(Data2Recv, 0, sizeof(Data2Recv));
		len = (short)UDP_Recv_Any_Bytes(&sock, Data2Recv, PACK_MAXNUM);
		if (len == -1)
			continue;

		//< 解析报文
		RecvNetIOBc_ANA(Data2Recv, len, Head, Tail);
	}
	close(sock);//< 断开连接

#undef PACK_MAXNUM
}


//************************************
// Method:    	BcNetIO_PACK_Make			站间广播点广播打包程序
// Programmer:  lww
// Time:		2019/2/16
// Returns:   	int							打包长度
// Parameter: 	void * Data					数据包头指针
// Parameter: 	short Head					报头
// Parameter: 	short Tail					报尾
// Parameter: 	int Limit_Len				单次数据包长度限制
// Parameter: 	short * SaveChannel_Num		存储的IO通道的数量
//************************************
int BcNetIO_PACK_Make(void* Data, short Head, short Tail, int Limit_Len, short* SaveChannel_Num)
{
#define MEMWRITE1(name)	MEMWRITE(name, Data);
	int _iLen = 0;
	short tmp_short;
	static int i = 0;
	NETAO_T* base_NETAO;
	NETDO_T* base_NETDO;
	void* Data1 = NULL;
	Channel_type_e type;

	//< 报头
	MEMWRITE1(Head);

	//< 站号
	MEMWRITE1(Station_ID);

	//< 第三个数据存放从下一个数据开始从后数多少个字节为报尾，用于对报文的报尾进行校验，此处先保留该存储位置，稍后再对其进行存储
	Data1 = Data;
	tmp_short = 0;
	MEMWRITE1(tmp_short);
	_iLen = (int)(_iLen - sizeof(tmp_short));

	//< 第四个数据存储本次要广播的点数量，这个数据等打包完成后最后写入，此处先保留该存储位置，稍后再对其进行存储
	MEMWRITE1(SaveChannel_Num[0]);
	_iLen = (int)(_iLen - sizeof(SaveChannel_Num[0])); //后面计算第三个数据存放从下一个数据开始从后数多少个字节为报尾时，要加上此长度

	for ( ; i < Model_List[TYPE(NETAO)].iCount + Model_List[TYPE(NETDO)].iCount; i++)
	{
		if (i < Model_List[TYPE(NETAO)].iCount)
		{
			base_NETAO = (NAME(NETAO)*)SearchAt(((List_Base_t*)Model_List[TYPE(NETAO)].ppData[0]), i);
			if (base_NETAO != NULL)
			{
				type = AO_CHA;
				MEMWRITE1(type);
				MEMWRITE1(base_NETAO->Base.List_Base.ID);
				MEMWRITE1(base_NETAO->Base.In.AI[0][0]);
				SaveChannel_Num[0]++;
			}
		}
		else
		{
			base_NETDO = (NAME(NETDO)*)SearchAt(((List_Base_t*)Model_List[TYPE(NETDO)].ppData[0]), i - Model_List[TYPE(NETAO)].iCount);
			if (base_NETAO != NULL)
			{
				type = DO_CHA;
				MEMWRITE1(type);
				MEMWRITE1(base_NETDO->Base.List_Base.ID);
				MEMWRITE1(base_NETDO->Base.In.DI[0][0]);
				SaveChannel_Num[0]++;
			}
		}
		if (_iLen > Limit_Len)
			break;
	}
	if (i >= Model_List[TYPE(NETAO)].iCount + Model_List[TYPE(NETDO)].iCount)
		i = 0;

	//< 写第三个数据
	tmp_short = (short)(_iLen - sizeof(Head) - sizeof(unsigned char) + sizeof(SaveChannel_Num[0]));//< 等于目前已经计数的长度减去报头，加上要广播模块数量数据的长度
	MEMWRITE(tmp_short, Data1);

	//< 写第四个数据
	MEMWRITE(SaveChannel_Num[0], Data1);

	//< 报尾
	MEMWRITE1(Tail);
	return _iLen;
#undef MEMWRITE1
}


//************************************
// Method:    	tBcNetIOAndRecvBc		站间引用点广播及接收广播线程
// Programmer:  lww
// Time:		2019/3/6
// Returns:   	void *
// Parameter: 	void * arg
//************************************
void * tBcNetIOAndRecvBc(void* arg)
{
#define PACK_MAXNUM	2048
#define LIMIT_LEN	512

	int sock;
	struct sockaddr_in NetA;
	struct sockaddr_in NetB;
	timer_t BcNetIO_Timer;
	struct timespec time;
	short Head = 7555;				//< 报头
	short Tail = 7576;				//< 报尾
	char Data2Send[PACK_MAXNUM];	//< 存放数据包的数组
	int _iLen = 0;
	short SaveChannel_Num = 0;		//< 当前数据包广播的IO通道数量
	pthread_t tRecvNetIOBc_ID = 0;

	printf("the Kernel_%s is %d\r\n", "tBcNetIOAndRecvBc_ID", syscall(SYS_gettid));			//< duan20200610
	//< 初始化UDP设置
	if (false == UDP_Init(&sock, BCNETIO_PORT, 0, 0, UDP_SEND_STATUS, nullptr)) { return 0; }

	//< 开启接收站间引用广播的线程
	THREAD_CREATE_FAILED(Thread_Create("tRecvNetIOBc_ID", &tRecvNetIOBc_ID, NULL, SCHED_POLICY, 89, true, tRecvNetIOBc, CONTROL_CORE, NULL));

	//< 设置发送到的IP地址及端口
	Addr_Set(&NetA, BCNETIO_PORT, inet_addr(NETA_IP_BC));
	Addr_Set(&NetB, BCNETIO_PORT, inet_addr(NETB_IP_BC));

	//< 设置广播周期
	MS2TimeSpec(&time, BCNETIO_PERIOD);

	//< 开启定时中断
	Timer_Create(&BcNetIO_Timer, BcNetIOSIG, &time);
	while (1)
	{
		if (SYS_Role == Master_Twins_Role || SYS_Role == Master_Alone_Role)
		{
			//< 等待信号量释放进行广播操作
			/*MUTEX_LOCK(BcNetIO_Mutex, "BcNetIO_Mutex lock failed");*/
			SEM_WAIT(BcNetIOSemId, "BcNetIOSemId wait failed");

			SaveChannel_Num = 0;
			//< 数据打包
			_iLen = BcNetIO_PACK_Make(Data2Send, Head, Tail, LIMIT_LEN, &SaveChannel_Num);

			if (SaveChannel_Num > 0)
			{
				//< 发送数据
				UDP_Send(&sock, &NetA, (char*)Data2Send, _iLen);
				UDP_Send(&sock, &NetB, (char*)Data2Send, _iLen);
			}
		}
		else
			RoughDelay_S(2);
	}
	close(sock);//< 断开连接
#undef LIMIT_LEN
#undef PACK_MAXNUM
}
